package com.boil.qz.safekavass.shiro.filter;

import com.boil.qz.safekavass.model.LoginUser;
import com.boil.qz.safekavass.pojo.MenuVo;
import com.boil.qz.safekavass.pojo.RoleResourceVo;
import com.boil.qz.safekavass.service.LoginUserService;
import com.boil.qz.safekavass.service.PermissionService;
import com.boil.qz.safekavass.service.ResourceService;
import com.boil.qz.safekavass.websocket.WebSocketTextServer;
import com.boil.util.Constants;
import com.boil.util.Utils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.SavedRequest;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Created by ChenYong on 2017-05-03.
 * <br>
 * 登录表单认证过滤器。
 */
public class LoginFormAuthenticationFilter extends FormAuthenticationFilter {
    /**
     * 日志
     */
    private static Logger log = LoggerFactory.getLogger(LoginFormAuthenticationFilter.class);
    /**
     * 注入用户 Service
     */
    @Autowired
    private LoginUserService loginUserService;
    /**
     * 注入资源 Service
     */
    @Autowired
    private ResourceService resourceService;
    /**
     * 注入权限 Service
     */
    @Autowired
    private PermissionService permissionService;
    /**
     * 注入 WebSocket 文本服务器
     */
    @Autowired
    private WebSocketTextServer webSocketTextServer;

    /**
     * 登录成功。
     *
     * @param token    令牌
     * @param subject  用户
     * @param request  请求
     * @param response 响应
     * @return 是否登录成功：
     * <li>
     * <ol>true-是；</ol>
     * <ol>false-否。</ol>
     * </li>
     * @throws Exception 抛出异常
     */
    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, //
                                     Subject subject, //
                                     ServletRequest request, //
                                     ServletResponse response) throws Exception {
        // 登录 Token
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        // 获取 Session
        Session session = subject.getSession();
        // 获取登录账号
        String account = usernamePasswordToken.getUsername();
        // 获取登录用户的信息
        LoginUser loginUser = loginUserService.findByLoginid(account);
        // 获取登录用户的菜单
        List<MenuVo> loginUserMenus = resourceService.getUserMenus(loginUser.getId());
        // 查询登录用户的角色资源关联
        List<RoleResourceVo> roleResourceVos = permissionService.findRoleResourceByUserId(loginUser.getId());
        // 登录用户拥有的角色
        Set<String> loginUserRoles = new HashSet<String>();
        // 登录用户拥有的权限
        Set<String> loginUserPerms = new HashSet<String>();

        // 整理角色和权限
        for (RoleResourceVo roleResourceVo : roleResourceVos) {
            loginUserRoles.add(roleResourceVo.getRoleCode());
            loginUserPerms.add(roleResourceVo.getPermissionCode());
        }

        // 将用户信息存入 Session 中
        session.setAttribute(Constants.LOGIN_USER, loginUser);
        // 将登录用户的所有菜单存入 Session 中
        session.setAttribute(Constants.LOGIN_USER_MENUS, loginUserMenus);
        // 将登录用户的所有角色存入 session 中
        session.setAttribute(Constants.LOGIN_USER_ROLES, Utils.parseList2Str(new ArrayList<String>(loginUserRoles), Constants.SPLIT_1));
        // 将登录用户的所有权限存入 session 中
        session.setAttribute(Constants.LOGIN_USER_PERMS, Utils.parseList2Str(new ArrayList<String>(loginUserPerms), Constants.SPLIT_1));

        Constants.ONLINE_SESSION_CACHE.add(session);

        /*
        // 结果映射
        ResultVo resultVo = new ResultVo();
        resultVo.setResultCode(Constants.ONLINE_SESSION_COUNT);
        resultVo.setResultMsg(Constants.ONLINE_SESSION_COUNT_MSG);
        resultVo.setResult(Constants.ONLINE_SESSION_CACHE.size());

        // 告诉所有客户端，有人登录啦
        webSocketTextServer.sendMessage(resultVo);
        */

        log.info("账号：{}--->登录成功", account);

        //----------[登录成功后，指定跳转操作]----------//
        // 从 Session 中获取上一次请求
        SavedRequest prevRequest = (SavedRequest) session.getAttribute(WebUtils.SAVED_REQUEST_KEY);

        if (prevRequest != null) {
            String requestURI = (StringUtils.isBlank(prevRequest.getRequestURI()) ? Constants.EMPTY_STR : prevRequest.getRequestURI());

            // 如果 Shiro 记录的上一次请求是退出登录的请求，那么先清空上一次请求，再重定向到首页
            if (requestURI.contains(Constants.URL_LOGOUT)) {
                // 清空上一次请求
                WebUtils.getAndClearSavedRequest(request);
                // 重定向到首页
                WebUtils.redirectToSavedRequest(request, response, Constants.URL_INDEX);

                // 必须返回 false
                return Constants.VALUE_FALSE;
            }
        }
        //----------[/登录成功后，指定跳转操作]----------//

        // 必须返回 false
        return super.onLoginSuccess(usernamePasswordToken, subject, request, response);
    }
}